package app

import (
	"github.com/goAdminMicroService/internal/pkg/transports/grpc"
	"github.com/goAdminMicroService/internal/pkg/transports/http"
	"github.com/pkg/errors"
	"go.uber.org/zap"
	"os"
	"os/signal"
	"syscall"
)

// 公用的应用的

type Application struct {
	name       string // 应用名称
	logger     *zap.Logger
	httpServer *http.Server
	grpcServer *grpc.Server
}

type Option func(app *Application) error

func HttpServerOption(svr *http.Server) Option {
	return func(app *Application) error {
		svr.Application(app.name)
		app.httpServer = svr
		return nil
	}
}

func GrpcServerOption(svr *grpc.Server) Option {
	return func(app *Application) error {
		svr.Application(app.name)
		app.grpcServer = svr
		return nil
	}
}

func New(name string, logger *zap.Logger, options ...Option) (*Application, error) {
	app := &Application{
		name:   name,
		logger: logger.With(zap.String("type", "Application")),
	}
	for _, option := range options {
		if err := option(app); err != nil {
			return nil, err
		}
	}
	return app, nil
}

// 启动项目
func (a *Application) Start() error {
	if a.httpServer != nil {
		// 启动服务
		if err := a.httpServer.Start(); err != nil {
			return errors.Wrap(err, "httpServer 启动失败")
		}
	}

	if a.grpcServer != nil {
		if err := a.grpcServer.Start(); err != nil {
			return errors.Wrap(err, "grpc server start error")
		}
	}
	return nil
}

// 停止程序 通过接收信号
func (a *Application) AwaitSignal() {
	// 创建一个接收信号的通道
	c := make(chan os.Signal, 1)
	// kill 默认会发送 syscall.SIGTERM 信号
	// Ctrl+C就是触发系统SIGINT信号
	signal.Reset(syscall.SIGTERM, syscall.SIGINT)
	signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)

	// 获取信号通道 这里还有阻塞作用
	select {
	case s := <-c:
		a.logger.Info("退出程序products", zap.String("signal", s.String()))
		if a.httpServer != nil {
			if err := a.httpServer.Stop(); err != nil {
				a.logger.Warn("停止http服务失败", zap.Error(err))
			}
		}

		if a.grpcServer != nil {
			if err := a.grpcServer.Stop(); err != nil {
				a.logger.Warn("stop grpc server error", zap.Error(err))
			}
		}
		// 退出程序
		os.Exit(0)
	}
}
